package com.sky.service.impl;

import com.sky.dto.GoodsSalesDTO;
import com.sky.entity.Orders;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.UserMapper;
import com.sky.service.ReportService;
import com.sky.service.WorkspaceService;
import com.sky.vo.*;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ReportServiceImpl implements ReportService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private WorkspaceService workspaceService;

    /**
     * 营业额统计
     * @param begin
     * @param end
     * @return
     */
    @Override
    public TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end) {
        //得到横坐标的日期 存放到 localDates 中
        List<LocalDate> localDates = new ArrayList<>();

        localDates.add(begin);
        while (!begin.equals(end)){
            begin = begin.plusDays(1);
            localDates.add(begin);
        }

        //用于存放 每天的 营业额数据（用于纵坐标展示）
        List<Double> doubleList = new ArrayList<>();

        //循环localDates中的数据 得到每一天的日期
        for (LocalDate localDate : localDates) {

            //一天的开始时间
            LocalDateTime beginTime = LocalDateTime.of(localDate, LocalTime.MIN);
            //一天的结束时间
            LocalDateTime endTime = LocalDateTime.of(localDate, LocalTime.MAX);

            Map map = new HashMap();
            map.put("beginTime",beginTime);
            map.put("endTime",endTime);
            map.put("ordersStatus", Orders.COMPLETED);

            //得到纵坐标的数据 每天的营业额，通过 一天的开始时间、一天的结束时间、状态
            Double oneDayTurnover = orderMapper.getTurnoverByMap(map);

            //把得到一天的营业额 存放到 doubleList中
            doubleList.add(oneDayTurnover);
        }

        //将List类型中的元素 拼接成 String 字符串，每个元素之间用 “,” 分隔
        String dateList = StringUtils.join(localDates, ",");
        String turnoverList = StringUtils.join(doubleList, ",");

        //将dateList、turnoverList 设置到 turnoverReportVO对象中
        TurnoverReportVO turnoverReportVO = new TurnoverReportVO();
        turnoverReportVO.setDateList(dateList);
        turnoverReportVO.setTurnoverList(turnoverList);

        return turnoverReportVO;
    }

    /**
     * 用户统计接口
     * @param begin
     * @param end
     * @return
     */
    @Override
    public UserReportVO userStatistics(LocalDate begin, LocalDate end) {
        //日期列表
        List<LocalDate> dateList = new ArrayList<>();
        dateList.add(begin);
        while (!begin.equals(end)){
            begin = begin.plusDays(1);
            dateList.add(begin);
        }

        //每天 新增用户数列表
        List<Integer> newUserList = new ArrayList<>();
        //每天 总共用户数列表
        List<Integer> totalUserList = new ArrayList<>();

        //遍历 日期列表
        for (LocalDate localDate : dateList) {
            LocalDateTime beginTime = LocalDateTime.of(localDate, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(localDate, LocalTime.MAX);
            //统计出来，每天新增的人数
            Integer newUserNum = getUserNum(beginTime, endTime);
            //统计出来，总共的人数
            Integer totalUserNum = getUserNum(null, endTime);
            newUserList.add(newUserNum);
            totalUserList.add(totalUserNum);
        }

        //将 日期列表 新增用户数列表 总共用户数列表 中的数据 拼接成String字符串 元素中间用","分隔
        String strDateList = StringUtils.join(dateList, ",");
        String strNewUserList = StringUtils.join(newUserList, ",");
        String strTotalUserList = StringUtils.join(totalUserList, ",");

        //将拼接成 String字符串的 各个列表 添加到 UserReportVO 对象中
        UserReportVO userReportVO = new UserReportVO();
        userReportVO.setDateList(strDateList);
        userReportVO.setNewUserList(strNewUserList);
        userReportVO.setTotalUserList(strTotalUserList);

        return userReportVO;
    }

    /**
     * 得到用户的数量
     * @param beginTime
     * @param endTime
     * @return
     */
    private Integer getUserNum(LocalDateTime beginTime,LocalDateTime endTime){
        Integer userNumber = userMapper.getUserNum(beginTime,endTime);
        return userNumber;
    }

    /**
     * 订单统计接口
     * @param begin
     * @param end
     * @return
     */
    @Override
    public OrderReportVO ordersStatistics(LocalDate begin, LocalDate end) {
        //得到日期列表
        List<LocalDate> dateList = new ArrayList<>();
        dateList.add(begin);
        while (!begin.equals(end)){
            begin = begin.plusDays(1);
            dateList.add(begin);
        }

        //得到每日订单列表
        List<Integer> orderCountList = new ArrayList<>();
        //得到每日有效订单列表
        List<Integer> validOrderCountList = new ArrayList<>();
        //遍历 日期列表
        for (LocalDate localDate : dateList) {
            //一天的开始时间
            LocalDateTime beginTime = LocalDateTime.of(localDate, LocalTime.MIN);
            //一天的结束时间
            LocalDateTime endTime = LocalDateTime.of(localDate, LocalTime.MAX);
            //得到每天的订单数量
            Integer orderCount = getOrdersCount(beginTime, endTime, null);
            //得到每天有效的订单数量
            Integer validOrderCount = getOrdersCount(beginTime, endTime, Orders.COMPLETED);

            //将得到的 订单数量 和 有效订单数量 存入 相应列表中
            orderCountList.add(orderCount);
            validOrderCountList.add(validOrderCount);
        }

        //将 日期列表、每日订单列表、每日有效订单列表 转化为 String类型，元素之间用“,”分隔
        String strDateList = StringUtils.join(dateList, ",");
        String strOrderCountList = StringUtils.join(orderCountList, ",");
        String strValidOrderCountList = StringUtils.join(validOrderCountList, ",");

        //得到订单总数
        Integer totalOrderCount = orderCountList.stream().reduce(Integer::sum).get();

        //得到有效订单总数
        Integer totalValidOrderCount = validOrderCountList.stream().reduce(Integer::sum).get();

        //得到订单完成率
        Double orderCompletionRate = totalOrderCount == 0 ? 0.0 :  totalValidOrderCount.doubleValue() / totalOrderCount;


        //返回数据
        OrderReportVO orderReportVO = OrderReportVO.builder()
                .dateList(strDateList)
                .orderCountList(strOrderCountList)
                .validOrderCountList(strValidOrderCountList)
                .totalOrderCount(totalOrderCount)
                .validOrderCount(totalValidOrderCount)
                .orderCompletionRate(orderCompletionRate)
                .build();

        return orderReportVO;
    }

    /**
     * 得到订单数量
     * @param beginTime
     * @param endTime
     * @param ordersStatus
     * @return
     */
    private Integer getOrdersCount(LocalDateTime beginTime,LocalDateTime endTime,Integer ordersStatus){
        Integer ordersCount = orderMapper.getOrdersCount(beginTime,endTime,ordersStatus);
        return ordersCount;
    }

    /**
     * 查询销量排名top10接口
     * @param begin
     * @param end
     * @return
     */
    @Override
    public SalesTop10ReportVO getSalesTop10(LocalDate begin, LocalDate end) {
        //将begin转换为一天中的开始时间  将end转换为一天中的结束时间
        LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);

        //查询数据库中的数据 得到 Top10 销量
        List<GoodsSalesDTO> goodsSalesDTOList = orderMapper.getSalesTop10(beginTime,endTime);

        //将List<GoodsSalesDTO> 中的 name 和 number 属性 转换成各自类型的List
        List<String> nameList = goodsSalesDTOList.stream().map(GoodsSalesDTO::getName).collect(Collectors.toList());
        List<Integer> numberList = goodsSalesDTOList.stream().map(GoodsSalesDTO::getNumber).collect(Collectors.toList());

        //将 nameList、numberList 转换成 String类型，元素之间用 “,” 分隔
        String strNameList = StringUtils.join(nameList, ",");
        String strNumberList = StringUtils.join(numberList, ",");

        //将 strNameList、strNumberList 封装到 SalesTop10ReportVO 对象中
        SalesTop10ReportVO salesTop10ReportVO = new SalesTop10ReportVO();
        salesTop10ReportVO.setNameList(strNameList);
        salesTop10ReportVO.setNumberList(strNumberList);

        return salesTop10ReportVO;
    }

    /**
     * 导出Excel报表接口
     * @param response
     */
    @Override
    public void export(HttpServletResponse response) {
        //定义 开始日期 和 结束日期
        LocalDate beginDate = LocalDate.now().minusDays(30);
        LocalDate endDate = LocalDate.now().minusDays(1);

        //定义 开始日期 的 最早时间
        LocalDateTime beginDateTime = LocalDateTime.of(beginDate, LocalTime.MIN);

        //定义 结束日期 的 最晚时间
        LocalDateTime endDateTime = LocalDateTime.of(endDate, LocalTime.MAX);

        //获得概览数据
        BusinessDataVO overviewData = workspaceService.getBusinessData(beginDateTime,endDateTime);

        //获得excel模板
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx");

        try {
            //在内存中创建 excel
            XSSFWorkbook excel = new XSSFWorkbook(inputStream);
            XSSFSheet sheet1 = excel.getSheet("sheet1");
            sheet1.getRow(1).getCell(1).setCellValue(beginDate+" 至 "+endDate);
            XSSFRow row3 = sheet1.getRow(3);
            row3.getCell(2).setCellValue(overviewData.getTurnover());
            row3.getCell(4).setCellValue(overviewData.getOrderCompletionRate());
            row3.getCell(6).setCellValue(overviewData.getNewUsers());

            XSSFRow row4 = sheet1.getRow(4);
            row4.getCell(2).setCellValue(overviewData.getValidOrderCount());
            row4.getCell(4).setCellValue(overviewData.getUnitPrice());

            //for循环 写入 明细数据
            for (int i=0; i<30; i++){
                LocalDate date = beginDate.plusDays(i);
                //获得date的最早时间，获得data的最晚时间
                LocalDateTime dateTimeBegin = LocalDateTime.of(date, LocalTime.MIN);
                LocalDateTime dateTimeEnd = LocalDateTime.of(date, LocalTime.MAX);

                //获得 某一天 的 明细数据
                BusinessDataVO detailDayData = workspaceService.getBusinessData(dateTimeBegin, dateTimeEnd);
                XSSFRow row = sheet1.getRow(7 + i);
                row.getCell(1).setCellValue(date.toString());
                row.getCell(2).setCellValue(detailDayData.getTurnover());
                row.getCell(3).setCellValue(detailDayData.getValidOrderCount());
                row.getCell(4).setCellValue(detailDayData.getOrderCompletionRate());
                row.getCell(5).setCellValue(detailDayData.getUnitPrice());
                row.getCell(6).setCellValue(detailDayData.getNewUsers());
            }
            //通过 输出流 将 文件下载到客户端 浏览器中
            ServletOutputStream outputStream = response.getOutputStream();
            excel.write(outputStream);

            //关闭资源
            outputStream.flush();
            outputStream.close();
            excel.close();

        } catch (IOException e) {
            throw new RuntimeException(e);
        }


    }
}
